package com.niiwoo.civet.trade.service.dubbo.loan.core;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.dubbo.rpc.RpcException;
import com.alibaba.fastjson.JSON;
import com.niiwoo.civet.account.dto.response.AccountBaseResponse;
import com.niiwoo.civet.account.service.AccountDubboService;
import com.niiwoo.civet.base.enums.DeadlineUnitEnum;
import com.niiwoo.civet.trade.dao.entity.Project;
import com.niiwoo.civet.trade.dao.entity.ProjectInvesting;
import com.niiwoo.civet.trade.dao.entity.ProjectPushRecord;
import com.niiwoo.civet.trade.dto.request.loan.PushProjectRequestDTO;
import com.niiwoo.civet.trade.enums.ProjectStatusEnum;
import com.niiwoo.civet.trade.enums.RepaymentTypeEnum;
import com.niiwoo.civet.trade.enums.TradeConfigEnum;
import com.niiwoo.civet.trade.service.local.common.ProjectCommonService;
import com.niiwoo.civet.trade.service.local.configure.TradeConfigLocalService;
import com.niiwoo.civet.trade.service.local.loan.SpeedLoanService;
import com.niiwoo.civet.user.dto.request.JPushExtDTO;
import com.niiwoo.civet.user.dto.request.UserLetterRequestDTO;
import com.niiwoo.civet.user.enums.JPushEnum;
import com.niiwoo.civet.user.enums.MessageTemplateKeyEnum;
import com.niiwoo.civet.user.enums.SMSTemplateKeyEnum;
import com.niiwoo.civet.user.enums.UserLetterTypeEnum;
import com.niiwoo.civet.user.service.SendSmsDubboService;
import com.niiwoo.civet.user.service.UserLetterDubboService;
import com.niiwoo.tripod.lanmao.component.LanMaoDirectService;
import com.niiwoo.tripod.lanmao.component.LanMaoSequence;
import com.niiwoo.tripod.lanmao.enums.ProjectTypeEnum;
import com.niiwoo.tripod.lanmao.enums.ResponseCodeEnum;
import com.niiwoo.tripod.lanmao.enums.ResponseStatusEnum;
import com.niiwoo.tripod.lanmao.enums.UserRoleEnum;
import com.niiwoo.tripod.lanmao.request.EstablishProjectRequest;
import com.niiwoo.tripod.lanmao.request.QueryProjectInformationRequest;
import com.niiwoo.tripod.lanmao.response.LanMaoResponse;
import com.niiwoo.tripod.lanmao.response.QueryProjectInformationResponse;
import com.niiwoo.tripod.provider.exception.BizException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

/**
 * @Description: 极速借内核：推标
 * @Author:xiaoyaocai
 * @Date:2018/04/20
 */
@Slf4j
public abstract class AbstractSpeedLoan implements ISpeedLoanService {

    @Autowired
    private ProjectCommonService projectCommonService;
    //@Reference(version = "1.0.0")

    AccountDubboService accountDubboService;
    @Reference(version = "1.0.0")
    public void setAccountDubboService(AccountDubboService accountDubboService) {
        this.accountDubboService = accountDubboService;
    }
    public AccountDubboService getAccountDubboService() {
        return accountDubboService;
    }

    @Autowired
    private LanMaoDirectService lanMaoDirectService;
    @Autowired
    private LanMaoSequence lanMaoSequence;
    @Autowired
    private SpeedLoanService loanLocalService;
    @Autowired
    private TradeConfigLocalService tradeConfigService;

    private UserLetterDubboService userLetterDubboService;


    @Reference(version = "1.0.0")
    public void setUserLetterDubboService(UserLetterDubboService userLetterDubboService) {
        this.userLetterDubboService = userLetterDubboService;
    }
    public UserLetterDubboService getUserLetterDubboService() {
        return userLetterDubboService;
    }

    private SendSmsDubboService sendSmsDubboService;

    @Reference(version = "1.0.0")
    public void setSendSmsDubboService(SendSmsDubboService sendSmsDubboService) {
        this.sendSmsDubboService = sendSmsDubboService;
    }
    public SendSmsDubboService getSendSmsDubboService() {
        return sendSmsDubboService;
    }
    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Override
    public void pushProject(PushProjectRequestDTO pushProjectRequestDTO) {
        try {
            Project project = projectCommonService.queryProjectBasicInfo(pushProjectRequestDTO.getProjectId());
            if (project == null) {
                throw new BizException("TRD20001");
            }

            if(!project.getStatus().equals(ProjectStatusEnum.CHECKING.getStatus())){
                //补偿机制上标
                if(pushProjectRequestDTO.getProjectPushRecordId()!=null){
                    loanLocalService.deletePushProjectRecordById(pushProjectRequestDTO.getProjectPushRecordId());
                }
                throw new BizException("TRD60003");
            }


            AccountBaseResponse accountBaseResponse = getAccountBase(project);

            QueryProjectInformationRequest queryProjectInformationRequest=new QueryProjectInformationRequest();
            queryProjectInformationRequest.setProjectNo(String.valueOf(pushProjectRequestDTO.getProjectId()));
            log.info("推标,标的ID={},开始调用查询存管标的信息接口,请求参数={}", pushProjectRequestDTO.getProjectId(), JSON.toJSONString(queryProjectInformationRequest));
            CompletableFuture<QueryProjectInformationResponse> completableFuture4QueryProejct = lanMaoDirectService.queryProjectInformation(queryProjectInformationRequest);
            QueryProjectInformationResponse queryProjectInformationResponse=completableFuture4QueryProejct.get();
            log.info("推标,标的ID={},结束调用查询存管标的信息接口,响应结果={}", pushProjectRequestDTO.getProjectId(), JSON.toJSONString(queryProjectInformationResponse));
            //1.成功;
            if (ResponseCodeEnum.SUCCESS.getValue().equals(queryProjectInformationResponse.getCode())
                    && ResponseStatusEnum.SUCCESS.getValue().equals(queryProjectInformationResponse.getStatus())) {
                if(queryProjectInformationResponse.getProjectStatus()!=null ){
                    //若存管已上标,且标的状态为COLLECTING(募集中),则直接进行本地业务上标操作;
                    if(queryProjectInformationResponse.getProjectStatus().equals(com.niiwoo.tripod.lanmao.enums.ProjectStatusEnum.COLLECTING)) {
                        pushProjectSuccess(pushProjectRequestDTO, project);
                    }
                    //若存管标的状态不为COLLECTING(募集中)状态,则证明此时流程已经出问题,直接进行错误日志记录;
                    else{
                        log.error("推标,标的ID={},发生异常,原因是上标时存管标的状态不为募集中状态,存管标的信息={}", pushProjectRequestDTO.getProjectId(), JSON.toJSONString(queryProjectInformationResponse));
                        //场景一：补偿机制上标;
                        if (pushProjectRequestDTO.getProjectPushRecordId() != null) {
                            loanLocalService.deletePushProjectRecordById(pushProjectRequestDTO.getProjectPushRecordId());
                            log.error("推标,标的ID={},t_tc_project_push_record表ID={},已删除对应t_tc_project_push_record表记录", pushProjectRequestDTO.getProjectId(),pushProjectRequestDTO.getProjectPushRecordId());
                            return;
                        }
                        //场景二：正常途径上标;
                        else{
                            throw new BizException("TRD40004");
                        }
                    }
                }
            }
            //若查询存管标的信息失败,则不做操作,且记录失败情况;
            else {
                //若存管无此标的信息,则进行存管与业务上标操作;
                EstablishProjectRequest establishProjectRequest = transProject2EstablishProjectRequest(project);
                establishProjectRequest.setPlatformUserNo(accountBaseResponse.getAccountNo());
                log.info("推标,标的ID={},开始调用存管上标接口,请求参数={}", pushProjectRequestDTO.getProjectId(), establishProjectRequest);
                CompletableFuture<LanMaoResponse> completableFuture = lanMaoDirectService.establishProject(establishProjectRequest);
                LanMaoResponse response = completableFuture.get();
                log.info("推标,标的ID={},开始调用存管上标接口,响应结果={}", pushProjectRequestDTO.getProjectId(), response);
                //1.成功;
                if (ResponseCodeEnum.SUCCESS.getValue().equals(response.getCode())
                        && ResponseStatusEnum.SUCCESS.getValue().equals(response.getStatus())) {
                    pushProjectSuccess(pushProjectRequestDTO, project);
                }
                //2.失败;
                else {
                    log.error("推标,标的ID={},存管上标失败,原因={}", pushProjectRequestDTO.getProjectId(), JSON.toJSONString(response));
                    ProjectPushRecord projectPushRecord=new ProjectPushRecord();
                    projectPushRecord.setId(pushProjectRequestDTO.getProjectPushRecordId());
                    projectPushRecord.setProjectNo(String.valueOf(pushProjectRequestDTO.getProjectId()));
                    projectPushRecord.setStatus(ProjectPushRecord.StatusEnum.FAIL.getStatus());
                    projectPushRecord.setErrorCode(response.getErrorCode());
                    projectPushRecord.setErrorMsg(response.getErrorMessage());
                    projectPushRecord.setErrorStatus(response.getStatus());
                    projectPushRecord.setAuditManagerId(pushProjectRequestDTO.getAuditManagerId());
                    projectPushRecord.setAuditManagerName(pushProjectRequestDTO.getAuditManagerName());
                    projectPushRecord.setAuditedTime(pushProjectRequestDTO.getAuditedTime());
                    projectPushRecord.setPushFrom(pushProjectRequestDTO.getPushFromEnum().getType());
                    projectPushRecord.setCreateTime(new Date());

                    compensate(projectPushRecord);
                }
            }
        } catch (Exception e) {
            //若为存管调用超时(即ExecutionException)或系统内服务调用超时(即RpcException),则需要进行重试;
            log.error("推标,标的ID={},发生系统异常,错误信息={}", pushProjectRequestDTO.getProjectId(), e);
            ProjectPushRecord projectPushRecord=new ProjectPushRecord();
            projectPushRecord.setId(pushProjectRequestDTO.getProjectPushRecordId());
            projectPushRecord.setProjectNo(String.valueOf(pushProjectRequestDTO.getProjectId()));
            projectPushRecord.setStatus(ProjectPushRecord.StatusEnum.FAIL.getStatus());
            projectPushRecord.setAuditManagerId(pushProjectRequestDTO.getAuditManagerId());
            projectPushRecord.setAuditManagerName(pushProjectRequestDTO.getAuditManagerName());
            projectPushRecord.setAuditedTime(pushProjectRequestDTO.getAuditedTime());
            projectPushRecord.setPushFrom(pushProjectRequestDTO.getPushFromEnum().getType());
            projectPushRecord.setCreateTime(new Date());

            compensate(projectPushRecord);

            throw new RuntimeException(e);
        }
    }

    /**
     * 上标补偿
     * @param projectPushRecord
     */
    public void compensate(ProjectPushRecord projectPushRecord){
        //场景一：补偿机制上标;
        if (projectPushRecord.getId() != null) {
            projectPushRecord.setUpdateTime(new Date());
            loanLocalService.updatePushProjectRecordStatus(projectPushRecord);
        }
        //场景二：后台人工审核通过上标;
        else {
            //录入审核失败记录;
            loanLocalService.initProejctPushRecord(projectPushRecord);
        }
    }

    protected void pushProjectSuccess(PushProjectRequestDTO pushProjectRequestDTO, Project project){
        project.setPublishTime(new Date());
        ProjectInvesting projectInvesting = new ProjectInvesting();
        projectInvesting.setProjectId(project.getProjectId());
        projectInvesting.setBorrowUserId(project.getBorrowUserId());
        projectInvesting.setBorrowHeadImage(project.getBorrowHeadImage());
        projectInvesting.setBorrowNickName(project.getBorrowNickName());
        projectInvesting.setBorrowGender(project.getBorrowGender());
        projectInvesting.setBorrowNiiwooScore(project.getBorrowNiiwooScore());
        projectInvesting.setLoanTimes(project.getLoanTimes());
        projectInvesting.setTitle(project.getTitle());
        projectInvesting.setContractAmount(project.getContractAmount());
        projectInvesting.setInvestedAmount(project.getInvestedAmount());
        projectInvesting.setBorrowRate(project.getBorrowRate());
        projectInvesting.setDeadline(project.getDeadline());
        projectInvesting.setDeadlineUnit(project.getDeadlineUnit());
        projectInvesting.setType(project.getType());
        projectInvesting.setLongitude(project.getLongitude());
        projectInvesting.setLatitude(project.getLatitude());
        projectInvesting.setLoanCity(project.getLoanCity());
        projectInvesting.setLoanArea(project.getLoanArea());
        Date now=new Date();
        projectInvesting.setPublishTime(now);
        projectInvesting.setRepaymentType(project.getRepaymentType());
        projectInvesting.setChannelCode(project.getChannelCode());
        projectInvesting.setCreateTime(now);
        projectInvesting.setCreditType(project.getCreditType());
        projectInvesting.setBorrowerType(project.getBorrowerType());
        projectInvesting.setOrgId(project.getOrgId());
        projectInvesting.setLoanType(project.getLoanType());
        projectInvesting.setInvestEndTime(project.getInvestEndTime());

        loanLocalService.pushProjectSuccess(project, projectInvesting, pushProjectRequestDTO,getProjectDateTime(project));

        sendInstationInfo(project);
    }

    /**
     * 获取配置Key
     * @return TradeConfigEnum
     */
    protected TradeConfigEnum getTradeConfigEnum(){
         return TradeConfigEnum.INVESTDEADLINE ;
    }

    /**
     * 根据用户标的信息获取用户账户
     * @param project
     * @return AccountBaseResponse
     */
    protected AccountBaseResponse getAccountBase(Project project){
        AccountBaseResponse accountBaseResponse = accountDubboService.getNiiwooAccount(project.getBorrowUserId(), UserRoleEnum.BORROWERS);
        if (accountBaseResponse == null) {
            throw new BizException("TRD40002");
        }
        return accountBaseResponse;
    }

    /**
     * 获取项目的投标起止时间
     * 必须指定 Map-key startDateTime,endDateTime
     * @param project
     * @return
     */
    protected Map<String,Date> getProjectDateTime(Project project){
         Map<String,Date> dtMap = new HashMap<>();
         Date startDateTime = new Date();
         String investDeadline = tradeConfigService.selectTradeConfigByEmun(getTradeConfigEnum()); //-- default:TradeConfigEnum.INVESTDEADLINE
         if(StringUtils.isEmpty(investDeadline)){
             log.info("推标,标的ID={},筹款期限未配置.", project.getProjectId());
             throw new RuntimeException("筹款期限未配置.");
         }
         Date endDateTime = org.apache.commons.lang3.time.DateUtils.addDays(startDateTime,Integer.valueOf(investDeadline));
         dtMap.put("startDateTime",startDateTime);
         dtMap.put("endDateTime",endDateTime);
         return dtMap;
    }

    /**
     * 发送站内信息
     * @param project
     */
    protected void sendInstationInfo(Project project){
         try{
             //2.发送[借款进入投资阶段]站内信、极光推送、短信;
             UserLetterRequestDTO userLetterRequestDTO = new UserLetterRequestDTO();
             userLetterRequestDTO.setLetterTemplateEnum(MessageTemplateKeyEnum.LetterTemplateKeyEnum.SPEED_LOAN_ENTER_INVEST);
             List<Object> letterTemplateParamList = new ArrayList<Object>();
             letterTemplateParamList.add(project.getProjectId());
             letterTemplateParamList.add(project.getTitle());
             userLetterRequestDTO.setLetterTemplateParamList(letterTemplateParamList);

             userLetterRequestDTO.setJpushTemplateKeyEnum(MessageTemplateKeyEnum.JPushTemplateKeyEnum.SPEED_LOAN_ENTER_INVEST);
             List<Object> jpushTemplateParamList = new ArrayList<Object>();
             jpushTemplateParamList.add(project.getTitle());
             userLetterRequestDTO.setJpushTemplateParamList(jpushTemplateParamList);
             userLetterRequestDTO.setToUserId(project.getBorrowUserId());
             userLetterRequestDTO.setProjectId(project.getProjectId());
             userLetterRequestDTO.setUserLetterTypeEnum(UserLetterTypeEnum.LETTER_AND_JPUSH);
             JPushExtDTO jpushExtDTO = new JPushExtDTO();
             jpushExtDTO.setRedirectPageEnum(JPushEnum.RedirectPageEnum.NOTICE_LIST_PAGE);
             userLetterRequestDTO.setJPushExt(jpushExtDTO);
             userLetterDubboService.pushLetter(userLetterRequestDTO);
             List<Object> params = new ArrayList<Object>();
             params.add(project.getTitle());
//             sendSmsDubboService.sendSmsByUserId(project.getBorrowUserId(), SMSTemplateKeyEnum.TEMP_SPEED_LOAN_ENTER_INVEST.getKey(), params);
         }catch(Exception e){
             log.info("推标,标的ID={},发送站内信息发生系统异常,原因={}", project.getProjectId(), e);
         }
    }

    private EstablishProjectRequest transProject2EstablishProjectRequest(Project project){
        EstablishProjectRequest establishProjectRequest=new EstablishProjectRequest();
        establishProjectRequest.setRequestNo(lanMaoSequence.getRequestNo());
        establishProjectRequest.setProjectNo(String.valueOf(project.getProjectId()));
        establishProjectRequest.setProjectAmount(project.getContractAmount());
        establishProjectRequest.setProjectName(project.getTitle());
        establishProjectRequest.setProjectDescription(project.getTitle());
        establishProjectRequest.setProjectType(ProjectTypeEnum.STANDARDPOWDER);
        establishProjectRequest.setProjectPeriod(project.getDeadlineUnit().equals(DeadlineUnitEnum.BY_DAY.getDeadlineUnit())?project.getDeadline():project.getDeadline()*30);
        establishProjectRequest.setAnnnualInterestRate(project.getBorrowRate().divide(BigDecimal.valueOf(100)));
        establishProjectRequest.setRepaymentWay(loanLocalService.transRepaymentType2LM(RepaymentTypeEnum.enumOf(project.getRepaymentType())));
        return establishProjectRequest;
    }


}
